#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
测试用例生成器
"""
import os
import shutil
from typing import Text, Dict

from config import Config
from common import logger
from custom.myexceptions import ValueNotFoundError
from util.file import get_all_files
from util.file.yaml_control import GetYamlData
from util.generator.case_template import write_testcase_file
from util.generator.config_generator import ConfTestGeneration


class TestCaseAutomaticGeneration:
    """自动生成自动化测试中的test_case代码"""

    def __init__(self, project_name):
        self.project_name = project_name
        self.data_path = Config.case_data_path
        self.case_path = Config.case_script_path
        self.project_path = os.path.join(self.case_path, self.project_name)
        logger.info(self.project_path)
        if not os.path.exists(self.project_path):
            os.makedirs(self.project_path)
        else:
            self.empty_files()

    def empty_files(self):
        """
        在重新生成新的用例文件前，先清空旧数据，达到同步最新接口用例文件
        :return:
        """
        for file in os.listdir(self.project_path):
            if file.endswith("py") or file == "__pycache__":
                continue
            dir_path = os.path.join(self.project_path, file)
            shutil.rmtree(dir_path)

    def convert_file_path_and_name(self, file: Text):
        """
        通过 yaml文件的命名，将名称转换成 py文件的名称
        :param file: C:\Sourcetree\InterfaceTest\test_case_data\example_project\example_module\example_interface.yaml
        :return:  示例: C:\Sourcetree\InterfaceTest\test_case\example_project\example_module\test_example_interface.py test_example_interface.py
        """
        i = len(self.data_path)
        yaml_path = file[i:]
        file_name = None
        # 路径转换
        if '.yaml' in yaml_path:
            file_name = yaml_path.replace('.yaml', '.py')
        elif '.yml' in yaml_path:
            file_name = yaml_path.replace('.yml', '.py')
        path = file_name.split(os.sep)
        file_name = path[-1] = path[-1].replace(path[-1], "test_" + path[-1])
        file_path = self.case_path + os.sep.join(path)
        return file_path, file_name

    def get_class_title(self, file_name: Text):
        """
        自动生成类名称
        :param file_path:
        :return: sup_apply_list --> SupApplyList
        """
        # 提取文件名称
        _file_name = file_name[:-3]
        _name = _file_name.split("_")
        _name_len = len(_name)
        # 将文件名称格式，转换成类名称: sup_apply_list --> SupApplyList
        for i in range(_name_len):
            _name[i] = _name[i].capitalize()
        _class_name = "".join(_name)
        return _class_name

    @staticmethod
    def error_message(param_name, file_path):
        """
        用例中填写不正确的相关提示
        :return:
        """
        msg = f"用例中未找到 {param_name} 参数值，请检查新增的用例中是否填写对应的参数内容" \
              "如已填写，可能是 yaml 参数缩进不正确\n" \
              f"用例路径: {file_path}"
        return msg

    @staticmethod
    def allure_epic(case_data: Dict, file_path) -> Text:
        """
        用于 allure 报告装饰器中的内容 @allure.epic("项目名称")
        :param case_data: 用例数据
        :param file_path: 用例路径
        :return:
        """
        try:
            return case_data['case_common']['allureEpic']
        except KeyError as exc:
            raise ValueNotFoundError(TestCaseAutomaticGeneration.error_message(
                param_name="allureEpic",
                file_path=file_path
            )) from exc

    @staticmethod
    def allure_feature(case_data: Dict, file_path) -> Text:
        """
        用于 allure 报告装饰器中的内容 @allure.feature("模块名称")
        :param case_data: 用例数据
        :param file_path: 用例路径
        :return:
        """
        try:
            return case_data['case_common']['allureFeature']
        except KeyError as exc:
            raise ValueNotFoundError(TestCaseAutomaticGeneration.error_message(
                param_name="allureFeature",
                file_path=file_path
            )) from exc

    @staticmethod
    def allure_story(case_data: Dict, file_path) -> Text:
        """
        用于 allure 报告装饰器中的内容  @allure.story("测试功能")
        :param case_data: 用例数据
        :param file_path: 用例路径
        :return:
        """
        try:
            return case_data['case_common']['allureStory']
        except KeyError as exc:
            raise ValueNotFoundError(TestCaseAutomaticGeneration.error_message(
                param_name="allureStory",
                file_path=file_path
            )) from exc

    def mk_dir(self, file_path: Text) -> None:
        """
        判断生成自动化代码的文件夹路径是否存在，如果不存在，则自动创建
        """
        _case_dir_path = os.path.split(file_path)[0]
        if not os.path.exists(_case_dir_path):
            os.makedirs(_case_dir_path)

    @staticmethod
    def case_ids(test_case):
        """
        获取用例 ID
        :param test_case: 测试用例内容
        :return:
        """
        ids = []
        for k, v in test_case.items():
            if k != "case_common":
                ids.append(k)
        return ids

    def gen_case_automatic(self) -> None:
        """ 自动生成 测试代码"""
        file_path = get_all_files(file_path=os.path.join(self.data_path, self.project_name), yaml_data_switch=True)
        logger.info(file_path)
        for file in file_path:
            # 判断代理拦截的yaml文件，不生成test_case代码
            if 'proxy_data.yaml' not in file:
                case_path, case_file_name = self.convert_file_path_and_name(file)
                # 判断用例需要用的文件夹路径是否存在，不存在则创建
                self.mk_dir(case_path)
                yaml_case_process = GetYamlData(file).get_yaml_data()
                write_testcase_file(
                    allure_epic=self.allure_epic(case_data=yaml_case_process, file_path=file),
                    allure_feature=self.allure_feature(case_data=yaml_case_process, file_path=file),
                    allure_story=self.allure_story(case_data=yaml_case_process, file_path=file),
                    class_title=self.get_class_title(case_file_name),
                    func_title=case_file_name[:-3],
                    case_path=case_path,
                    case_ids=self.case_ids(yaml_case_process),
                    file_name=case_file_name,
                    project_name=self.project_name
                )
        ConfTestGeneration(self.project_name)


if __name__ == '__main__':
    TestCaseAutomaticGeneration("example_project").gen_case_automatic()
